package mediaindex

import (
	"gitlab.local/DO-module/new-filemanage-module/src/core/httplogger"
	"gitlab.local/DO-module/new-filemanage-module/src/core/sqlitedb/sqlitemodel"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/goccy/go-json"
	"github.com/gogf/gf/errors/gerror"
	"gitlab.local/golibrary/utils"

	"github.com/gin-gonic/gin"

	"github.com/pkg/errors"
)

// MediaServer 启动/关闭多媒体服务
// isenable 0-停用；1-启用
func (mi *MediaIndex) MediaServer(c *gin.Context, isenable int) bool {
	logger := httplogger.New()
	if isenable == 0 {
		if !mi.MediaServerStatus() {
			return true
		}
		_, err := utils.ShellExec(Minidlnad, "stop")
		if err != nil {
			return false
		}
		if utils.Exists("/etc/sc.d/minidlnad") {
			_ = os.Remove("/etc/sc.d/minidlnad")
		}
		logger.Infoln(c, httplogger.DisabledMedia)
		return true
	}

	isRestart := "start"
	if mi.MediaServerStatus() {
		isRestart = "restart"
	}
	_, err := utils.ShellExec(Minidlnad, isRestart)
	if err != nil {
		return false
	}
	if !utils.Exists("/etc/sc.d/minidlnad") {
		_, _ = os.Create("/etc/sc.d/minidlnad")
	}
	logger.Infoln(c, httplogger.EnabledMedia)
	return true
}

// 获取多媒体服务程序运行状态
func (mi *MediaIndex) MediaServerStatus() bool {
	cmd, err := utils.ShellExec(Minidlnad, "status")
	if err != nil {
		return false
	}
	if strings.Contains(cmd, "stopped") {
		return false
	}
	return true
}

// GetMediaList 获取媒体索引目录列表
func (mi *MediaIndex) GetMediaList() (result []MediaIndexList, errResult error) {
	res, err := GetMediaJsonList()
	if err != nil {
		errResult = err
		return
	}
	if len(res) == 0 {
		return
	}
	db := mi.db.DbGet()
	var users []sqlitemodel.UserTable
	db.Table("user_table").Find(&users)
	for _, re := range res {
		if !utils.Exists(re.Path) {
			_ = mi.DelMediaIndex(re.Path, re.Name)
			continue
		}
		if strings.Contains(re.Path, "home") && filepath.Base(re.Path) != "home" {
			path := strings.Split(re.Path, "/")
			if len(path) < 3 {
				continue
			}

			userName := path[2]
			if !IsInUser(userName, users) {
				_ = mi.DelMediaIndex(re.Path, re.Name)
				continue
			}

			if path[1] == "home" {
				path[1] = "homes"
			}
			re.Path = strings.Join(path, "/")
		}
		result = append(result, re)
	}
	return
}

func IsInUser(user string, list []sqlitemodel.UserTable) bool {
	if user == "" {
		return true
	}
	for _, k := range list {
		if user == "admin" {
			return false
		}
		if k.Username == user {
			return true
		}
	}
	return false
}

// IsExitFolder 判断改添加索引目录是否已被添加
// true-存在；false-不存在
func (mi *MediaIndex) IsExitFolder(path string) bool {
	list, err := GetMediaJsonList()
	if err != nil {
		return false
	}
	for _, k := range list {
		if k.Path == path {
			return true
		}
	}
	return false
}

func AddMediaIndexContent(mil MediaIndexList) (int, error) {
	if !utils.Exists(MediaJsonConf) {
		_, err := os.Create(MediaJsonConf)
		if err != nil {
			return 0, errors.Wrap(err, "Creat MediaJsonConf failed")
		}
	}

	mediaList, err := GetMediaJsonList()
	if err != nil {
		return 0, errors.Wrap(err, "Get Medialist failed")
	}
	//判断此目录是否已经存在
	for _, m := range mediaList {
		if mil.Path == m.Path {
			return 0, errors.New("This Folder is exit")
		}
	}
	jsonList, err := json.Marshal(append(mediaList, mil))
	if err != nil {
		return 0, errors.Wrap(err, "JSON Marshal failed")
	}

	err = os.WriteFile(MediaJsonConf, jsonList, os.ModePerm)
	if err != nil {
		return 0, errors.Wrap(err, "WriteFile failed")
	}

	//添加索引目录至/etc/media.conf 文件
	var photo, music, video, text string
	if mil.Photo == "1" {
		photo = "P"
	}
	if mil.Music == "1" {
		music = "A"
	}
	if mil.Video == "1" {
		video = "V"
	}
	if mil.Text == "1" {
		text = "T"
	}
	pav := photo + music + video + text
	err = WriteMediaConf("add", mil.Path, pav)

	return 1, err
}

// AddMediaIndex 添加索引目录
func AddMediaIndex(mil MediaIndexList) (int, error) {
	index, err := AddMediaIndexContent(mil)
	return index, err
}

// AddFolderToMediaIndex only use for sharefolder,
// when create sharefolder(user click or running mkbase) will invoke it
// mntPath example: /Volume2/test4
func AddFolderToMediaIndex(mntPath string) error {
	mediaIndexList := MediaIndexList{
		Path:   mntPath,                // example: /Volume2/test4
		Name:   filepath.Base(mntPath), // example: test4
		L_name: filepath.Base(mntPath), // example: test4
		Photo:  "1",
		Music:  "1",
		Video:  "1",
		Text:   "1",
	}
	_, err := AddMediaIndex(mediaIndexList)
	return err
}

// EditMediaIndex 编辑索引信息
func (mi *MediaIndex) EditMediaIndex(mil MediaIndexList, c *gin.Context) (int, error) {
	if mil.Name == "" {
		return 0, nil
	}
	mediaList, err := GetMediaJsonList()
	if err != nil {
		return 0, errors.Wrap(err, "Get Medialist failed")
	}
	for i := range mediaList {
		changePath := strings.Replace(mil.Path, "/homes", "/home", 1)

		if changePath == mediaList[i].Path {
			mediaList[i].Photo = mil.Photo
			mediaList[i].Music = mil.Music
			mediaList[i].Video = mil.Video
			mediaList[i].Text = mil.Text
		}
	}

	jsonList, err := json.Marshal(mediaList)
	if err != nil {
		return 0, errors.Wrap(err, "JSON Marshal failed")
	}
	isAdd, err := utils.WriteFile(MediaJsonConf, string(jsonList))
	if err != nil || isAdd == 0 {
		return 0, errors.Wrap(err, "WriteFile failed")
	}

	//添加索引目录至/etc/media.conf 文件
	var photo, music, vedio, text string
	if mil.Photo == "1" {
		photo = "P"
	}
	if mil.Music == "1" {
		music = "A"
	}
	if mil.Video == "1" {
		vedio = "V"
	}
	if mil.Text == "1" {
		text = "T"
	}
	pav := photo + music + vedio + text
	err = WriteMediaConf("edit", mil.Path, pav)
	return 1, err
}

// DelMediaIndex 删除索引信息
func (mi *MediaIndex) DelMediaIndex(path, name string) error {
	mediaList, err := GetMediaJsonList()
	if err != nil {
		return gerror.Wrap(err, "Get Medialist failed")
	}
	var newList []MediaIndexList
	for _, media := range mediaList {
		deletePath := strings.Replace(path, "/homes", "/home", 1)

		if deletePath == media.Path {
			continue
		}
		newList = append(newList, media)
	}
	jsonList, err := json.Marshal(newList)
	if err != nil {
		return gerror.Wrap(err, "JSON Marshal failed")
	}
	if err = os.WriteFile(MediaJsonConf, jsonList, os.ModePerm); err != nil {
		return gerror.Wrap(err, "WriteFile failed")
	}

	//删除索引目录至/etc/media.conf 文件
	return WriteMediaConf("del", path, "")
}

// reset MediaIndex
func (mi *MediaIndex) ResetMediaIndex() (int, error) {

	utils.ShellExec(Minidlnad, "rescan")
	// 记录本次索引时间
	mi.lastIndex()
	return 1, nil
}

type Status struct {
	Status int   `json:"status"` //0 正在索引 1 索引完成 2 索引失败
	Count  int64 `json:"count"`
}

// GetMediaSearchStatus 获取媒体索引状态
func (mi *MediaIndex) GetMediaSearchStatus() Status {

	mainVol, err := utils.ShellWithString("mainvol")
	if err != nil {
		mainVol = "/Volume1"
	}

	scanningPath := filepath.Join(mainVol, "@system/media/scanning")
	completedPath := filepath.Join(mainVol, "@system/media/completed")

	var status Status
	minidlnad := mi.MediaServerStatus()
	if !minidlnad && utils.Exists(scanningPath) && !utils.Exists(completedPath) {

		// 媒体索引异常停止(还有就是正在索引的时候,重新开始)
		status.Status = 2
		return status
	}

	if utils.Exists(scanningPath) && !utils.Exists(completedPath) {

		status.Status = 0
		p, m, v, f := mi.CountFiles()
		status.Count = p + m + v + f
		return status
	}

	if !utils.Exists(scanningPath) && utils.Exists(completedPath) {

		// 媒体索引完成
		status.Status = 1
		return status
	}

	status.Status = 0
	return status
}

func (mi *MediaIndex) lastIndex() bool {
	ti := time.Now().Format("2006-01-02 15:04:05")
	if !utils.Exists("/usr/local/media") {
		err := os.Mkdir("/usr/local/media", os.ModePerm)
		if err != nil {
			return false
		}
	}
	if !utils.Exists(LastIndex) {
		_, err := os.Create(LastIndex)
		if err != nil {
			return false
		}
	}
	_, err := utils.WriteFile(LastIndex, ti)
	return err == nil
}

func (mi *MediaIndex) LastIndex() string {
	if !utils.Exists(LastIndex) {
		content, err := utils.ShellExec(`date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y-%m-%d %H:%M:%S"`)
		if err != nil {
			return ""
		}
		return strings.Split(content, "\n")[0]
	}
	return utils.GetFirstLine(LastIndex)
}

// GetMediaThumbnail 获取媒体索引缩略图配置
func (mi *MediaIndex) GetMediaThumbnail() (Thumbnail, error) {
	if !utils.Exists(ThumbnailConf) {
		return Thumbnail{}, nil
	}
	content := utils.GetFirstLine(ThumbnailConf)
	var conf Thumbnail
	err := json.Unmarshal([]byte(content), &conf)
	return conf, err
}

// SetMediaThumbnail 设置媒体索引缩略图配置
func (mi *MediaIndex) SetMediaThumbnail(conf Thumbnail) error {
	if !utils.Exists(ThumbnailConf) {
		err := utils.TouchFile(ThumbnailConf)
		if err != nil {
			return err
		}
	}
	content, err := json.Marshal(conf)
	if err != nil {
		return err
	}
	_, err = utils.WriteFile(ThumbnailConf, string(content))
	return err
}

// CountFiles 获取索引文件个数
func (mi *MediaIndex) CountFiles() (int64, int64, int64, int64) {
	media, err := mi.start()
	if err != nil {
		return 0, 0, 0, 0
	}
	var photo, music, video, doc int64
	media.Table("photo").Count(&photo)
	media.Table("music").Count(&music)
	media.Table("video").Count(&video)
	media.Table("documents").Count(&doc)
	return photo - video, music, video, doc
}
